/*
 * Copyright (C) 2015-2017 Alibaba Group Holding Limited
 */

#include <stdio.h>
#include <stdint.h>

#include "k_config.h"
#include "k_api.h"
#include "aos/kernel.h"
#include "aos/hal/gpio.h"
#include "aos/hal/uart.h"
#include "aos/hal/i2c.h"
#include "aos/hal/can.h"

#include "pin_mux.h"
#include "fsl_wm8960.h"
#include "tca6424.h"
#include "hal_gpio.h"

#ifdef WITH_LWIP
#include "lwip/opt.h"
#include "lwip/netif.h"
#include "lwip/tcpip.h"
#include "lwip/inet.h"

#include "ethernetif.h"
#endif
#include "hal_uart.h"
#include "soc_init.h"

#if defined(__CC_ARM) && defined(__MICROLIB)
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#elif defined(__ICCARM__)
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#else
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(void)
#endif /* defined (__CC_ARM) && defined(__MICROLIB) */
int codec_i2c_init(void);

uart_mapping_s st_uart_mapping_table[PORT_UART_SIZE] =
{
    {PORT_UART_STD_P6, (void *)(LPUART1), 512},
    {PORT_UART_485_1, (void *)(LPUART2), 2048},
    {PORT_UART_485_2, (void *)(LPUART4), 2048},
    {PORT_UART_4G, (void *)(LPUART3), 1024 * 8},
    {PORT_UART_ZIGBEE, (void *)(LPUART8), 2048},
    {PORT_UART_P5, (void *)(LPUART6), 512},
};

const gpio_mapping_t gpio_mapping_table[] = {
    {PORT_GPIO_P8_6, {GPIO1, 25}, NULL},       /*P8 SPI CS*/
    {PORT_GPIO_P9_6, {GPIO1, 21}, NULL},       /*P9 SPI CS*/
    {PORT_GPIO_TCA_RST, {GPIO1, 20}, NULL},    /*tca6424 rst K12*/
    {PORT_GPIO_TCA_INT, {GPIO1, 24}, NULL},    /*tca6424 int H13*/
    {PORT_GPIO_TP_INT, {GPIO1, 0}, NULL},      /*lcd i2c tsc2007 intrrupt*/
    {PORT_GPIO_ETH_RST, {GPIO3, 5}, NULL},     /*phy reset N3*/
    {PORT_GPIO_SD1_CD, {GPIO2, 28}, NULL},      /*sd card detect pin D13*/
    {PORT_GPIO_DO_1, {(void *)0x00010022, TCA_PORT1_3}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_DO_2, {(void *)0x00010022, TCA_PORT1_2}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_DO_3, {(void *)0x00010022, TCA_PORT1_1}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_DO_4, {(void *)0x00010022, TCA_PORT1_0}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_DI_1, {(void *)0x00010022, TCA_PORT0_3}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_DI_2, {(void *)0x00010022, TCA_PORT0_2}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_DI_3, {(void *)0x00010022, TCA_PORT0_1}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_DI_4, {(void *)0x00010022, TCA_PORT0_0}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_S2_1, {(void *)0x00010022, TCA_PORT2_4}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_S2_2, {(void *)0x00010022, TCA_PORT2_5}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_S2_3, {(void *)0x00010022, TCA_PORT2_6}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_S2_4, {(void *)0x00010022, TCA_PORT2_7}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_4G_EN, {(void *)0x00010022, TCA_PORT1_5}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
    {PORT_GPIO_ZIGBEE_EN, {(void *)0x00010022, TCA_PORT1_4}, NULL},   /*base high 16 bit is i2c port , low 16 bit chip i2c addr*/
};

const uint32_t g_u32_gpio_num = ARRAY_SIZE(gpio_mapping_table);

can_mapping_t can_mapping_table[] =
{
    { PORT_CAN_IO,       CAN2, NULL, NULL, NULL },
    { PORT_CAN_RESERVED, CAN1, NULL, NULL, NULL }
};

/* Global Variable for VFS DEBUG Output */
uart_dev_t uart_0 = {
    .port = PORT_UART_STD_P6,                                                              /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

uart_dev_t uart_485_1 = {
    .port = PORT_UART_485_1,                                                            /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

/*can not be used at the same time with debug uart port*/
uart_dev_t uart_485_2 = {
    .port = PORT_UART_485_2,                                                            /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

uart_dev_t uart_4G = {
    .port = PORT_UART_4G,                                                               /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

uart_dev_t uart_zigbee = {
    .port = PORT_UART_ZIGBEE,                                                           /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

i2c_dev_t i2c_port_1 = {
    .port = 1,
    .config = {I2C_HAL_ADDRESS_WIDTH_7BIT, I2C_BUS_BIT_RATES_100K, I2C_MODE_MASTER, 0},
    .priv = NULL
};

#ifdef WITH_LWIP
extern struct netif fsl_netif0[];
#endif
extern void tcp_init(void);
extern void udp_init(void);

int lwip_tcpip_init(void);


gpio_mapping_t* get_drv_manu_info(gpio_dev_t *gpio)
{
    uint32_t i = 0;

    for (i = 0; i < g_u32_gpio_num; i++) {
        if (gpio_mapping_table[i].port == gpio->port) {
            return &gpio_mapping_table[i];
        }
    }

    return NULL;
}

const st_gpio_opt_t* get_gpio_opt(gpio_dev_t *gpio)
{
    /*mcu soc opt*/
    if (gpio->port < PORT_ONCHIP_GPIO_NUM) {
        return &g_stmimx_gpio_opt;
    } else {
        /*external module chip*/
        return &g_sttca6424_gpio_opt;
    }
}

static void stduart_init(void)
{
    hal_uart_init(&uart_0);
}

static void lte_power_on()
{
    int32_t ret = 0;
    gpio_dev_t st_4g_en = {0};

    st_4g_en.port = PORT_GPIO_4G_EN;
    st_4g_en.config = OUTPUT_PUSH_PULL;
    st_4g_en.priv = NULL;

    ret = hal_gpio_init(&st_4g_en);
    if (ret)
    {
        printf("GPIO 4G_EN init fail %d \r\n", ret);
        return;
    }

    ret = hal_gpio_output_high(&st_4g_en);
    if (ret)
    {
        printf("GPIO 4G_EN output high fail %d \r\n", ret);
        return;
    }

    return;
}

void board_peripheral_init(void)
{
    int32_t ret = 0;
    /*default uart init*/
    stduart_init();

    /*I2C PORT1 init*/
    ret = hal_i2c_init(&i2c_port_1);
    if (ret)
    {
        printf("i2c port 1 init fail \r\n");
    }

    /*init i2c to DIDO device*/
    ret = tca6426_device_init(PORT_GPIO_TCA_RST, PORT_GPIO_TCA_INT, 
                    i2c_port_1.port, TCA6424_I2C_ADDR_LOW);
    if (ret)
    {
        printf("tca6426_device_init init fail \r\n");
        aos_reboot();
    }

    #ifdef WITH_LWIP
    lwip_tcpip_init();
    #else
    /*power on 4g n720*/
    lte_power_on();
    #endif
}

/* Get debug console frequency. */
uint32_t BOARD_DebugConsoleSrcFreq(void)
{
    uint32_t freq;

    /* To make it simple, we assume default PLL and divider settings, and the only variable
       from application is use PLL3 source or OSC source */
    if (CLOCK_GetMux(kCLOCK_UartMux) == 0) /* PLL3 div6 80M */
    {
        freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
    }
    else
    {
        freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
    }

    return freq;
}

void platform_init(void)
{
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
}

#ifdef WITH_LWIP
static void tcpip_init_done(void *arg)
{
    long long ts = aos_now();
    srand((unsigned int)ts);
    tcp_init();
    udp_init();

#if LWIP_IPV4
    ip4_addr_t ipaddr, netmask, gw;
    memset(&ipaddr, 0, sizeof(ipaddr));
    memset(&netmask, 0, sizeof(netmask));
    memset(&gw, 0, sizeof(gw));
    ip4addr_aton("192.168.1.220", &ipaddr);
    ip4addr_aton("255.255.255.0", &netmask);
    ip4addr_aton("192.168.1.1", &gw);
    //gw = inet_addr("192.168.1.220");
    netif_add(&fsl_netif0[0], &ipaddr, &netmask, &gw, NULL, ethernetif0_init, tcpip_input);
#endif

#if LWIP_IPV6
#if !LWIP_IPV4
    netif_add(&fsl_netif0[0], NULL, ethernetif0_init, tcpip_input);
#endif
    netif_create_ip6_linklocal_address(&fsl_netif0[0], 1);
    fsl_netif0[0].ip6_autoconfig_enabled = 1;
#endif

    netif_set_default(&fsl_netif0[0]);
    netif_set_up(&fsl_netif0[0]);
    //tcpip_dhcpc_start(&fsl_netif0[0]);
    printf("TCP/IP initialized.");
}

int lwip_tcpip_init(void)
{
    tcpip_init(tcpip_init_done, NULL);

    return 0;
}
#endif

/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
    krhino_intrpt_enter();
    krhino_tick_proc();
    krhino_intrpt_exit();
}

/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
    if (ch == '\n')
    {
        //hal_uart_send(&console_uart, (void *)"\r", 1, 30000);
        hal_uart_send(&uart_0, (void *)"\r", 1, 30000);
    }
    hal_uart_send(&uart_0, &ch, 1, 30000);
    return ch;
}

/**
  * @brief  Retargets the C library scanf function to the USART.
  * @param  None
  * @retval None
  */
GETCHAR_PROTOTYPE
{
    /* Place your implementation of fgetc here */
    /* e.g. readwrite a character to the USART2 and Loop until the end of transmission */
    uint8_t ch = EOF;
    int32_t ret = -1;

    uint32_t recv_size;
    ret = hal_uart_recv_II(&uart_0, &ch, 1, &recv_size, HAL_WAIT_FOREVER);

    if (ret == 0)
    {
        return ch;
    }
    else
    {
        return -1;
    }
}



void io_exp_reinit(void){
    gpio_dev_t gpio={0};
    tca6424_device_deinit(PORT_GPIO_TCA_RST, PORT_GPIO_TCA_INT,i2c_port_1.port, TCA6424_I2C_ADDR_LOW);
    aos_msleep(10);
    for(int i=PORT_GPIO_P8_6;i<=PORT_GPIO_SD1_CD;i++){
        gpio.port=i;
        hal_gpio_finalize(&gpio);
    }
    for(int i=PORT_GPIO_DO_1;i<PORT_GPIO_SIZE;i++){
        gpio.port=i;
        hal_gpio_finalize(&gpio);
    }
    gpio.port=PORT_GPIO_P9_6;
    gpio.config=OUTPUT_PUSH_PULL;
    gpio.priv=NULL;
    hal_gpio_init(&gpio);
    hal_gpio_output_low(&gpio);
    aos_msleep(20);
    hal_gpio_output_high(&gpio);
    tca6426_device_init(PORT_GPIO_TCA_RST, PORT_GPIO_TCA_INT,i2c_port_1.port, TCA6424_I2C_ADDR_LOW);
    
}